// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/parser/ast/stmt.h>

namespace cantor::parser {

    nlohmann::ordered_json StmtNode::to_json_impl() const {
        auto j = Node::to_json_impl();
        j["stmt_type"] = StmtType_Name(stmt_type);
        return j;
    }

    nlohmann::ordered_json PragmaSetStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        nlohmann::ordered_json vars;
        for (int32_t i = 0; i < var_list.size(); i++) {
            vars.push_back(std::move(var_list[i]->to_json()));
        }
        j["vars"] = vars;
        return j;
    }

    void SelectStmt::to_stream(std::ostream &os) const {
        if (with != nullptr) {
            with->to_stream(os);
            os << " AS ";
        }
        if (is_in_braces) {
            os << "(";
        }
        os << "SELECT";
        select_opt->to_stream(os);
        for (int i = 0; i < fields.size(); ++i) {
            if (i != 0) {
                os << ",";
            }
            os << fields[i];
        }
        if (table_refs != nullptr) {
            os << " FROM";
            table_refs->to_stream(os);
        }
        if (where != nullptr) {
            os << " WHERE " << where;
        }
        if (group != nullptr) {
            os << " GROUP BY" << group;
        }
        if (having != nullptr) {
            os << " HAVING" << having;
        }
        if (order != nullptr) {
            os << " ORDER BY" << order;
        }
        if (limit != nullptr) {
            os << " LIMIT" << limit;
        }
        os << for_lock_str[lock];
        if (is_in_braces) {
            os << ")";
        }
    }

    void CreateTableStmt::set_def_element(Vector<TableDefElement *> *defs, turbo::Arena &arena) {
        if (defs != nullptr) {
            for (int i = 0; i < defs->size(); i++) {
                auto &ele = (*defs)[i];
                if (ele->column) {
                    columns.push_back(ele->column, arena);
                    continue;
                }
                if (ele->constrain) {
                    constraints.push_back(ele->constrain, arena);
                    continue;
                }
            }
        }
    }

    nlohmann::ordered_json CreateTableStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["if_not_exist"] = if_not_exist;
        if (table_name) {
            j["table_name"] = table_name->to_json();
        } else {
            j["table_name"] = nlohmann::ordered_json{};
        }
        if (ref_table_name) {
            j["ref_table_name"] = ref_table_name->to_json();
        } else {
            j["ref_table_name"] = nlohmann::ordered_json{};
        }

        auto cols = nlohmann::ordered_json::array();
        if (columns.size() > 0) {
            LocationInfo loc;
            loc.location = columns[0]->location.location;
            loc.len = columns[columns.size() - 1]->location.location + columns[columns.size() - 1]->location.len -
                      columns[0]->location.location;
            j["columns_location"] = loc.to_json();
        }
        for (auto i = 0; i < columns.size(); i++) {
            cols.push_back(columns[i]->to_json());
        }
        j["columns"] = cols;

        auto cons = nlohmann::ordered_json::array();
        if (constraints.size() > 0) {
            LocationInfo loc;
            loc.location = constraints[0]->location.location;
            loc.len = constraints[constraints.size() - 1]->location.location + constraints[constraints.size() - 1]->
                      location.len - constraints[0]->location.location;
            j["constraints_location"] = loc.to_json();
        }
        for (auto i = 0; i < constraints.size(); i++) {
            cons.push_back(constraints[i]->to_json());
        }
        j["constraints"] = cons;

        /// ops
        auto ops = nlohmann::ordered_json::array();
        if (options.size() > 0) {
            LocationInfo loc;
            loc.location = options[0]->location.location;
            loc.len = options[options.size() - 1]->location.location + options[options.size() - 1]->location.len -
                      options[0]->location.location;
            j["options_location"] = loc.to_json();
        }
        for (auto i = 0; i < options.size(); i++) {
            ops.push_back(options[i]->to_json());
        }
        j["options"] = ops;

        return j;
    }

    nlohmann::ordered_json AlterTableStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        if (table_name) {
            j["table_name"] = table_name->to_json();
        } else {
            j["table_name"] = nlohmann::ordered_json{};
        }
        j["ignore"] = ignore;
        auto specs = nlohmann::ordered_json::array();
        for (auto i = 0; i < alter_specs.size(); i++) {
            auto &spec = alter_specs[i];
            specs.push_back(spec->to_json());
        }
        j["alter_specs"] = specs;
        return j;
    }

    nlohmann::ordered_json CreateTypeStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        if (type_name) {
            j["type_name"] = type_name->to_json();
        } else {
            j["type_name"] = nlohmann::ordered_json{};
        }
        if (uri) {
            j["uri"] = uri->to_json();
        } else {
            j["uri"] = nlohmann::ordered_json{};
        }

        j["proto"] = proto.to_string();
        j["json"] = json.to_string();
        return j;
    }

    void LoadDataStmt::to_stream(std::ostream &os) const {
        os << "LOAD DATA ";
        if (is_local) {
            os << "LOCAL ";
        }
        os << "INFILE ";
        if (!path.empty()) {
            os << "'" << path << "' ";
        }
        switch (on_duplicate_handle) {
            case pb::ast::ON_DUPLICATE_KEY_ERROR:
            case pb::ast::ON_DUPLICATE_KEY_IGNORE:
                os << "IGNORE ";
                break;
            case pb::ast::ON_DUPLICATE_KEY_REPLACE:
                os << "REPLACE ";
                break;
        }
        os << "INTO TABLE ";
        table_name->to_stream(os);
        if (!char_set.empty()) {
            os << " CHARACTER SET " << char_set << " ";
        }
        if (fields_info != nullptr) {
            if (!fields_info->terminated.empty()) {
                if (fields_info->terminated.is_print()) {
                    os << "TERMINATED BY '" << fields_info->terminated << "'";
                } else {
                    os << "TERMINATED BY NONPRINT";
                }
            }
            if (!fields_info->enclosed.empty() && fields_info->enclosed.is_print()) {
                if (!fields_info->opt_enclosed) {
                    os << " ENCLOSED BY '" << fields_info->enclosed << "'";
                } else {
                    os << " OPTIONALLY ENCLOSED BY '" << fields_info->enclosed << "'";
                }
            } else if (!fields_info->enclosed.empty()) {
                os << "ENCLOSED BY NONPRINT";
            }
            if (!fields_info->escaped.empty() && fields_info->escaped.is_print()) {
                os << " ESCAPED BY '" << fields_info->escaped << "'";
            } else if (!fields_info->escaped.empty()) {
                os << "ESCAPED BY NONPRINT";
            }
        }
        if (lines_info != nullptr) {
            os << " LINES ";
            if (!lines_info->starting.empty() && lines_info->starting.is_print()) {
                os << "STARTING BY '" << lines_info->starting << "'";
            } else if (!lines_info->starting.empty()) {
                os << "STARTING BY NONPRINT";
            }
            if (!lines_info->terminated.empty() && lines_info->terminated.is_print()) {
                os << "TERMINATED BY '" << lines_info->terminated << "'";
            } else if (!lines_info->terminated.empty()) {
                os << "TERMINATED BY NONPRINT";
            }
        }
        if (ignore_lines > 0) {
            os << " IGNORE " << ignore_lines;
        }

        if (columns.size() > 0) {
            os << " (";
            for (int i = 0; i < columns.size(); i++) {
                columns[i]->to_stream(os);
                if (i < columns.size() - 1) {
                    os << ", ";
                }
            }
            os << ")";
        }
        if (set_list.size() > 0) {
            os << " SET ";
            for (int i = 0; i < set_list.size(); i++) {
                set_list[i]->to_stream(os);
                if (i < set_list.size() - 1) {
                    os << ", ";
                }
            }
        }
    }

    void DeleteStmt::to_stream(std::ostream &os) const {
        static const char *ignore_str[] = {"", " IGNORE"};
        static const char *quick_str[] = {"", " QUICK"};
        os << "DELETE";
        os << priority_str[priority];
        os << quick_str[is_quick] << ignore_str[is_ignore];
        if (delete_table_list.size() != 0) {
            for (int i = 0; i < delete_table_list.size(); ++i) {
                os << " ";
                delete_table_list[i]->to_stream(os);
                if (i != delete_table_list.size() - 1) {
                    os << ",";
                }
            }
        }
        os << " FROM ";
        if (from_table)
            from_table->to_stream(os);
        else
            table_name->to_stream(os);

        if (where != nullptr) {
            os << " WHERE ";
            where->to_stream(os);
        }
        if (order != nullptr) {
            os << " ORDER BY";
            order->to_stream(os);
        }
        if (limit != nullptr) {
            os << " LIMIT";
            limit->to_stream(os);
        }
    }

    void UnionStmt::to_stream(std::ostream &os) const {
        if (is_in_braces) {
            os << "(";
        }
        for (int i = 0; i < select_stmts.size(); i++) {
            select_stmts[i]->to_stream(os);
            if (i < select_stmts.size() - 1) {
                if (distinct) {
                    os << " UNION ";
                } else {
                    os << " UNION ALL ";
                }
            }
        }
        if (order != nullptr) {
            os << " ORDER BY" << order;
        }
        if (limit != nullptr) {
            os << " LIMIT" << limit;
        }
        os << for_lock_str[lock];
        if (is_in_braces) {
            os << ")";
        }
    }

    void UpdateStmt::to_stream(std::ostream &os) const {
        static const char *ignore_str[] = {"", " IGNORE"};
        os << "UPDATE";
        os << ignore_str[is_ignore];
        os << table_refs << " SET";
        for (int i = 0; i < set_list.size(); ++i) {
            os << " " << set_list[i];
            if (i != set_list.size() - 1) {
                os << ",";
            }
        }
        if (where != nullptr) {
            os << " WHERE " << where;
        }
        if (order != nullptr) {
            os << " ORDER BY" << order;
        }
        if (limit != nullptr) {
            os << " LIMIT" << limit;
        }
    }

    void InsertStmt::to_stream(std::ostream &os) const {
        static const char *desc_str[] = {" INSERT", " REPLACE"};
        static const char *ignore_str[] = {"", " IGNORE"};
        static const char *merge_str[] = {"", " MERGE"};
        os << desc_str[is_replace];
        os << priority_str[priority] << ignore_str[is_ignore] << merge_str[is_merge] << " INTO ";
        if (table_name != nullptr) {
            table_name->to_stream(os);
        }
        if (columns.size() > 0) {
            os << "(";
        }
        for (int i = 0; i < columns.size(); ++i) {
            columns[i]->to_stream(os);
            if (i != columns.size() - 1) {
                os << ", ";
            }
        }
        if (columns.size() > 0) {
            os << ")";
        }
        if (subquery_stmt != nullptr) {
            os << " ";
            subquery_stmt->to_stream(os);
            return;
        }
        os << " VALUES";
        if (turbo::get_flag(FLAGS_ast_print_sample)) {
            os << " (?) ";
        } else {
            for (int i = 0; i < lists.size(); ++i) {
                os << " ";
                lists[i]->to_stream(os);
                if (i != lists.size() - 1) {
                    os << ",";
                }
            }
        }
        if (on_duplicate.size() != 0) {
            os << " ON DUPLICATE KEY UPDATE";
        }
        for (int i = 0; i < on_duplicate.size(); ++i) {
            os << " ";
            on_duplicate[i]->to_stream(os);
            if (i != on_duplicate.size() - 1) {
                os << ",";
            }
        }
    }

    nlohmann::ordered_json SelectStmt::to_json() const {
        nlohmann::ordered_json j =StmtNode::to_json_impl();

        if (select_opt) {
            j["select_opt"] = select_opt->to_json();
        } else {
            j["select_opt"] = "";
        }
        /// fields
        auto json_fields = nlohmann::ordered_json::array();
        for (auto i = 0; i < fields.size(); ++i) {
            json_fields.push_back(fields[i]->to_json());
        }
        j["fields"] = json_fields;

        if (table_refs) {
            j["table_refs"] = table_refs->to_json();
        } else {
            j["table_refs"] = nlohmann::ordered_json();
        }
        if (where) {
            j["where"] = where->to_json();
        } else {
            j["where"] = nlohmann::ordered_json();
        }

        if (group) {
            j["group"] = group->to_json();
        } else {
            j["group"] = nlohmann::ordered_json();
        }
        if (having) {
            j["having"] = having->to_json();
        } else {
            j["having"] = nlohmann::ordered_json();
        }
        if (order) {
            j["order"] = order->to_json();
        }
        if (limit) {
            j["limit"] = limit->to_json();
        }
        if (with) {
            j["with"] = with->to_json();
        } else {
            j["with"] = nlohmann::ordered_json();
        }

        j["is_in_braces"] = is_in_braces;
        j["lock"] = static_cast<int>(lock);
        j["option"] = option.to_string();
        return j;
    }

    nlohmann::ordered_json UnionStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["distinct"] = distinct;

        auto selects = nlohmann::ordered_json::array();
        for (auto i = 0; i < select_stmts.size(); ++i) {
            selects.push_back(select_stmts[i]->to_json());
        }
        j["select_stmts"] = selects;
        if (order) {
            j["order"] = order->to_json();
        } else {
            j["order"] = nlohmann::ordered_json();
        }

        if (limit) {
            j["limit"] = limit->to_json();
        } else {
            j["limit"] = nlohmann::ordered_json();
        }
        j["lock"] = static_cast<int>(lock);
        j["is_in_braces"] = is_in_braces;
        return j;

    }

    nlohmann::ordered_json InsertStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["priority"] = static_cast<int>(priority);
        j["is_replace"] = is_replace;
        j["is_merge"] = is_merge;
        j["is_ignore"] = is_ignore;
        if (table_name) {
            j["table_name"] = table_name->to_json();
        } else {
            j["table_name"] = nlohmann::ordered_json();
        }

        if (subquery_stmt) {
            j["subquery_stmt"] = subquery_stmt->to_json();
        } else {
            j["subquery_stmt"] = nlohmann::ordered_json();
        }

        auto cols = nlohmann::ordered_json::array();
        for (auto i = 0; i < columns.size(); ++i) {
            cols.push_back(columns[i]->to_json());
        }
        j["columns"] = cols;

        auto rs = nlohmann::ordered_json::array();
        for (auto i = 0; i < lists.size(); ++i) {
            rs.push_back(lists[i]->to_json());
        }
        j["lists"] = rs;

        auto ps = nlohmann::ordered_json::array();
        for (auto i = 0; i < partition_names.size(); ++i) {
            ps.push_back(partition_names[i].to_string());
        }
        j["partition_names"] = ps;

        auto ds = nlohmann::ordered_json::array();
        for (auto i = 0; i < on_duplicate.size(); ++i) {
            ds.push_back(on_duplicate[i]->to_json());
        }
        j["on_duplicate"] = ds;
        return j;
    }

    nlohmann::ordered_json LoadDataStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["ignore_lines"] = ignore_lines;
        j["is_local"] = is_local;
        j["path"] = path.to_string();
        j["char_set"] = char_set.to_string();
        if (fields_info) {
            j["fields_info"] = fields_info->to_json();
        } else {
            j["fields_info"] = nlohmann::ordered_json();
        }
        if (lines_info) {
            j["lines_info"] = lines_info->to_json();
        } else {
            j["lines_info"] = nlohmann::ordered_json();
        }
        if (table_name) {
            j["table_name"] = table_name->to_json();
        } else {
            j["table_name"] = nlohmann::ordered_json();
        }
        j["on_duplicate_handle"] = on_duplicate_handle;

        auto cols = nlohmann::ordered_json::array();
        for (auto i = 0; i < columns.size(); ++i) {
            cols.push_back(columns[i]->to_json());
        }
        j["columns"] = cols;

        auto rs = nlohmann::ordered_json::array();
        for (auto i = 0; i < set_list.size(); ++i) {
            rs.push_back(set_list[i]->to_json());
        }
        j["set_list"] = rs;
        return j;
    }

    nlohmann::ordered_json CreateViewStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["or_replace"] = or_replace;
        if (view_name) {
            j["view_name"] = view_name->to_json();
        } else {
            j["view_name"] = nlohmann::ordered_json();
        }
        auto cols = nlohmann::ordered_json::array();
        for (auto i = 0; i < column_names.size(); ++i) {
            cols.push_back(column_names[i]->to_json());
        }
        j["columns"] = cols;
        if (view_select_stmt) {
            j["view_select_stmt"] = view_select_stmt->to_json();
        } else {
            j["view_select_stmt"] = nlohmann::ordered_json();
        }
        return j;
    }

    nlohmann::ordered_json RollbackTxnStmt::to_json() const {
        return StmtNode::to_json_impl();
    }


    nlohmann::ordered_json StartTxnStmt::to_json() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["read_only"] = read_only;
        return j;
    }

    nlohmann::ordered_json CommitTxnStmt::to_json() const {
        return StmtNode::to_json_impl();
    }

    nlohmann::ordered_json DeallocPrepareStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["name"] = name.to_string();
        return j;
    }

    nlohmann::ordered_json ExecPrepareStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["name"] = name.to_string();
        auto pl = nlohmann::ordered_json::array();
        for (auto i = 0; i < param_list.size(); ++i) {
            pl.push_back(param_list[i].to_string());
        }
        j["param_list"] = pl;
        return j;
    }

    nlohmann::ordered_json KillStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["conn_id"] = conn_id;
        j["is_query"] = is_query;
        return j;
    }

    nlohmann::ordered_json CreateNamespaceStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_not_exists"] = if_not_exists;
        j["ns_name"] = ns_name.to_string();
        auto ol = nlohmann::ordered_json::array();
        for (auto i = 0; i < options.size(); ++i) {
            ol.push_back(options[i]->to_json());
        }
        j["options"] = ol;
        return j;
    }

    nlohmann::ordered_json DropNamespaceStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exists"] = if_exists;
        j["ns_name"] = ns_name.to_string();
        return j;
    }
    nlohmann::ordered_json AlterNamespaceStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exists"] = if_exists;
        j["ns_name"] = ns_name.to_string();
        auto ol = nlohmann::ordered_json::array();
        for (auto i = 0; i < options.size(); ++i) {
            ol.push_back(options[i]->to_json());
        }
        j["options"] = ol;
        return j;
    }

    nlohmann::ordered_json CreateUserStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_not_exists"] = if_not_exists;
        auto sps = nlohmann::ordered_json::array();
        for (auto i = 0; i < specs.size(); ++i) {
            sps.push_back(specs[i]->to_json());
        }
        j["specs"] = sps;
        j["namespace_name"] = namespace_name.to_string();
        return j;
    }

    nlohmann::ordered_json DropUserStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exists"] = if_exists;

        auto sps = nlohmann::ordered_json::array();
        for (auto i = 0; i < specs.size(); ++i) {
            sps.push_back(specs[i]->to_json());
        }
        j["specs"] = sps;
        return j;
    }

    nlohmann::ordered_json AlterUserStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exists"] = if_exists;
        j["namespace_name"] = namespace_name.to_string();
        auto ol = nlohmann::ordered_json::array();
        for (auto i = 0; i < specs.size(); ++i) {
            ol.push_back(specs[i]->to_json());
        }
        j["specs"] = ol;
        return j;
    }

    nlohmann::ordered_json PrivStmt::to_json() const {
        auto j = StmtNode::to_json_impl();

        auto prs = nlohmann::ordered_json::array();
        for (auto i = 0; i < privs.size(); ++i) {
            prs.push_back(privs[i]->to_json());
        }
        j["privs"] = prs;
        if (priv_level) {
            j["priv_level"] = priv_level->to_json();
        } else {
            j["priv_level"] = nlohmann::ordered_json();
        }

        auto ol = nlohmann::ordered_json::array();
        for (auto i = 0; i < specs.size(); ++i) {
            ol.push_back(specs[i]->to_json());
        }
        j["specs"] = ol;
        j["with_grant"] = with_grant;
        j["namespace_name"] = namespace_name.to_string();
        return j;
    }

    nlohmann::ordered_json RevokeStmt::to_json() const {
        return PrivStmt::to_json();
    }
    nlohmann::ordered_json GrantStmt::to_json() const {
        return PrivStmt::to_json();
    }

    nlohmann::ordered_json UpdateStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["priority"] = cantor::pb::ast::PriorityEnum_Name(priority);
        j["is_ignore"] = is_ignore;
        if (table_refs) {
            j["table_refs"] = table_refs->to_json();
        } else {
            j["table_refs"] = nlohmann::ordered_json();
        }
        auto sl = nlohmann::ordered_json::array();
        for (auto i = 0; i < set_list.size(); ++i) {
            sl.push_back(set_list[i]->to_json());
        }
        j["sets"] = sl;
        if (where) {
            j["where"] = where->to_json();
        } else {
            j["where"] = nlohmann::ordered_json();
        }

        if (order) {
            j["order"] = order->to_json();
        } else {
            j["order"] = nlohmann::ordered_json();
        }
        if (limit) {
            j["limit"] = limit->to_json();
        } else {
            j["limit"] = nlohmann::ordered_json();
        }
        return j;
    }

    nlohmann::ordered_json TruncateStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["table_name"] = table_name->to_string();
        auto sps = nlohmann::ordered_json::array();
        for (auto i = 0; i < partition_names.size(); ++i) {
            sps.push_back(partition_names[i].to_string());
        }
        j["partition_names"] = sps;
        return j;
    }

    nlohmann::ordered_json DeleteStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["priority"] = cantor::pb::ast::PriorityEnum_Name(priority);
        j["is_ignore"] = is_ignore;
        j["is_quick"] = is_quick;
        if (from_table) {
            j["from_table"] = from_table->to_json();
        } else {
            j["from_table"] = nlohmann::ordered_json();
        }

        if (table_name) {
            j["table_name"] = table_name->to_json();
        } else {
            j["table_name"] = nlohmann::ordered_json();
        }
        auto dls = nlohmann::ordered_json::array();
        for (auto i = 0; i < delete_table_list.size(); ++i) {
            dls.push_back(delete_table_list[i]->to_json());
        }
        j["delete_table_list"] = dls;

        auto ps = nlohmann::ordered_json::array();
        for (auto i = 0; i < partition_names.size(); ++i) {
            ps.push_back(partition_names[i].to_string());
        }
        j["partition_names"] = ps;
        if (where) {
            j["where"] = where->to_json();
        } else {
            j["where"] = nlohmann::ordered_json();
        }

        if (order) {
            j["order"] = order->to_json();
        } else {
            j["order"] = nlohmann::ordered_json();
        }

        if (limit) {
            j["limit"] = limit->to_json();
        } else {
            j["limit"] = nlohmann::ordered_json();
        }
        return j;
    }

    nlohmann::ordered_json DropViewStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exist"] = if_exist;
        if (view_name) {
            j["view_name"] = view_name->to_json();
        } else {
            j["view_name"] = nlohmann::ordered_json();
        }
        return j;
    }

    nlohmann::ordered_json CreateDatabaseStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_not_exist"] = if_not_exist;
        j["db_name"] = db_name.to_string();
        auto ol = nlohmann::ordered_json::array();
        for (auto i = 0; i <options.size(); ++i) {
            ol.push_back(options[i]->to_json());
        }
        j["options"] = ol;
        return j;
    }

    nlohmann::ordered_json DropDatabaseStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exist"] = if_exist;
        j["db_name"] = db_name.to_string();
        return j;
    }

    nlohmann::ordered_json AlterViewStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        if (view_name) {
            j["view_name"] = view_name->to_json();
        } else {
            j["view_name"] = nlohmann::ordered_json();
        }
        if (view_select_stmt) {
            j["view_select_stmt"] = view_select_stmt->to_json();
        } else {
            j["view_select_stmt"] = nlohmann::ordered_json();
        }

        auto dls = nlohmann::ordered_json::array();
        for (auto i  = 0; i < column_names.size(); ++i) {
            dls.push_back(column_names[i]->to_json());
        }
        j["column_names"] = dls;
        return j;
    }

    nlohmann::ordered_json ExplainStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        if (stmt) {
            j["stmt"] = stmt->to_json();
        }
        j["format"] = format.to_string();
        return j;
    }

    nlohmann::ordered_json NewPrepareStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["name"] = name.to_string();
        j["sql"] = sql.to_string();
        return j;
    }

    nlohmann::ordered_json DropTableStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        j["if_exist"] = if_exist;
        auto ns = nlohmann::ordered_json::array();
        for (auto i = 0; i <table_names.size(); ++i) {
            ns.push_back(table_names[i]->to_json());
        }
        j["table_names"] = ns;
        return j;
    }

    nlohmann::ordered_json RestoreTableStmt::to_json() const {
        auto j = StmtNode::to_json_impl();
        auto ts = nlohmann::ordered_json::array();
        for (auto i = 0; i <table_names.size(); ++i) {
            ts.push_back(table_names[i]->to_json());
        }
        j["table_names"] = ts;
        return j;
    }
} // namespace cantor::parser
